home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 November / macformat-043.iso / mac / Shareware Plus / Developers / Sprite Animation Toolkit 2.3.8 / Add-ons / Sprite behavior / SATGridToolbox.p < prev    next >
Encoding:
Text File  |  1996-03-29  |  11.0 KB  |  352 lines  |  [TEXT/PJMM]

  1. {SATGridToolbox}
  2. {}
  3. {Routines for SAT-based games with a game world defined by a grid.}
  4. {Note that this is the "Oxyd"-style world, where movement isn't contrained to the grid,}
  5. {but obstacles etc are defined by it. It is NOT ment for strict grid movement, as in PacMan!}
  6. {}
  7. {Limitations and assumptions:}
  8. {• Your grid is defined in the unit SATGridStubs.}
  9. {• All free space grid values are smaller than the blocked ones. (Specified by kFreeSpace.) }
  10. {• Sprites should not be bigger (wider/higher) than the grid spaces. (Sprites only check with the}
  11. {corners of the hotRects, which mens that a small grid obstacle could pass right through it!)}
  12. {}
  13. {Idéer:}
  14. {• Lägg till rutiner för förflyttning och kollisionshantering i strikt grid. Eller skall det vara en}
  15. {egen modul?}
  16. {• Duger LoadGrid?}
  17. {• Prefix på namnen?}
  18.  
  19. unit SATGridToolbox;
  20.  
  21. interface
  22.  
  23.     uses
  24. {$IFC UNDEFINED THINK_PASCAL}
  25.         Types, QuickDraw, Fonts, Events, Packages, Menus, Dialogs, Windows,{}
  26.         OSUtils, ToolUtils, {OSEvents,}
  27.         Resources, 
  28. {$ENDC}
  29.         SAT, SATToolbox, SATGridStubs;
  30.  
  31.     procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
  32. {procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr); SKIT?}
  33.     function Pt2GridValue (p: Point): GridSpaceType;
  34.     procedure LoadGrid (resNum: Integer);
  35.     procedure DrawAllTiles;
  36.     function PtInGrid (p: Point): Boolean;
  37.     procedure GridTest (theSprite: FixSpritePtr);
  38.  
  39. implementation
  40.  
  41. {Load the grid from a TEXT resource.}
  42.     procedure LoadGrid (resNum: Integer);
  43.         type
  44.             CharArr = packed array[0..99999] of Char;
  45.             CharArrPtr = ^CharArr;
  46.             CharArrHnd = ^CharArrPtr;
  47.         var
  48.             hnd: CharArrHnd;
  49.             howMuch: Longint;
  50.             h, v: Integer;
  51.     begin
  52.         hnd := CharArrHnd(GetResource('TEXT', resNum));
  53.         if hnd = nil then
  54.             exit(LoadGrid);
  55.         if GetHandleSize(Handle(hnd)) > SizeOf(tileArray) then
  56.             howMuch := SizeOf(tileArray)
  57.         else
  58.             howMuch := GetHandleSize(Handle(hnd));
  59.  
  60.         HLock(Handle(hnd));
  61.  
  62.         h := 0;
  63.         v := 0;
  64.         howMuch := 0;
  65.  
  66.         while howMuch < GetHandleSize(Handle(hnd)) do
  67.             begin
  68.                 if hnd^^[howMuch] = Char(13) then
  69.                     begin
  70.                         h := 0;
  71.                         v := v + 1;
  72.                     end
  73.                 else
  74.                     begin
  75.                         if h < kArraySizeH then
  76.                             if v < kArraySizeV then
  77.                                 tileArray[h, v] := hnd^^[howMuch];
  78.                         h := h + 1;
  79.                     end;
  80.  
  81.                 howMuch := howMuch + 1;
  82.             end;
  83.  
  84.         HUnLock(Handle(hnd));
  85.  
  86. {BlockMove(Ptr(hnd^), @tileArray[0, 0], howMuch);}
  87.         ReleaseResource(Handle(hnd));
  88.     end; {LoadGrid}
  89.  
  90. {PtInGrid: is the point blocked or free?}
  91. {Needs improving: several different grid values should be free!}
  92.  
  93.     function PtInGrid (p: Point): Boolean;
  94.     begin
  95.         PtInGrid := tileArray[p.h div kTileSizeH][p.v div kTileSizeV] > kFreeSpace;
  96.     end; (*PtInGrid*)
  97.  
  98.  
  99. {Get the grid value in a point. A sprite can, for example, test with its center!}
  100.  
  101.     function Pt2GridValue (p: Point): GridSpaceType;
  102.     begin
  103.         Pt2GridValue := tileArray[p.h div kTileSizeH][p.v div kTileSizeV];
  104.     end; (*Pt2GridValue*)
  105.  
  106.     procedure GetGridRect (p: Point; var r: Rect);
  107.     begin
  108.         SetRect(r, p.h div kTileSizeH * kTileSizeH, p.v div kTileSizeV * kTileSizeV, (p.h div kTileSizeH + 1) * kTileSizeH, (p.v div kTileSizeV + 1) * kTileSizeV);
  109.     end; (*GetGridRect*)
  110.  
  111.     function RectSeparateRect (theSprite: SpritePtr; var anotherRect: Rect): Integer;
  112.         var
  113.             distance: array[0..3] of Integer;
  114.             shortest, shortestDistance, i: Integer;
  115.             bounds1, bounds2: Rect;
  116.     begin
  117.         bounds1 := theSprite^.hotRect;
  118.         OffsetRect(bounds1, theSprite^.position.h, theSprite^.position.v);
  119.  
  120.         bounds2 := anotherRect;
  121.  
  122. (*Calculate the distance to separate the sprites in every direction*)
  123.         distance[0] := bounds2.top - bounds1.bottom; {up}
  124.         distance[1] := bounds2.bottom - bounds1.top; {down}
  125.         distance[2] := bounds2.right - bounds1.left; {right}
  126.         distance[3] := bounds2.left - bounds1.right; {left}
  127.  
  128. (*Find the shortest distance*)
  129.         shortest := 0;
  130.         shortestDistance := abs(distance[0]);
  131.         for i := 1 to 3 do
  132.             if abs(distance[i]) < shortestDistance then
  133.                 begin
  134.                     shortest := i;
  135.                     shortestDistance := abs(distance[i]);
  136.                 end;
  137.  
  138. (*Move the sprite in the appropriate direction*)
  139.         case shortest of
  140.             0, 1: 
  141.                 theSprite^.position.v := theSprite^.position.v + distance[shortest];
  142.             2, 3: 
  143.                 theSprite^.position.h := theSprite^.position.h + distance[shortest];
  144.         end; {case}
  145.         RectSeparateRect := shortest;
  146.     end; (*RectSeparateRect*)
  147.  
  148.  
  149. {GridTest: A complex function that tests whether a sprite is in free space or not, and bounces}
  150. {off grid obstacles if not.}
  151.  
  152.     procedure GridTest (theSprite: FixSpritePtr);
  153.         var
  154.             p1, p2, p3, p4: Point;
  155.             bounds, gridRect: Rect;
  156.             sum: Integer;
  157.     begin
  158.         sum := 0;
  159.         bounds := theSprite^.hotRect;
  160.         OffsetRect(bounds, theSprite^.position.h, theSprite^.position.v);
  161.         p1 := bounds.topLeft;
  162.         p2.h := bounds.left;
  163.         p2.v := bounds.bottom;
  164.         p3.h := bounds.right;
  165.         p3.v := bounds.top;
  166.         p4 := bounds.botRight;
  167.  
  168.         if PtInGrid(p1) then
  169.             sum := sum + 1;
  170.         if PtInGrid(p2) then
  171.             sum := sum + 2;
  172.         if PtInGrid(p3) then
  173.             sum := sum + 4;
  174.         if PtInGrid(p4) then
  175.             sum := sum + 8;
  176.  
  177.         case sum of
  178.             0, 15: 
  179.                 Exit(GridTest);
  180. { Single corner}
  181.             1: 
  182.                 begin
  183.                     GetGridRect(p1, gridRect);
  184.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  185.                         theSprite^.speed.h := abs(theSprite^.speed.h)
  186.                     else
  187.                         theSprite^.speed.v := abs(theSprite^.speed.v);
  188.                 end;
  189.             2: 
  190.                 begin
  191.                     GetGridRect(p2, gridRect);
  192.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  193.                         theSprite^.speed.h := abs(theSprite^.speed.h)
  194.                     else
  195.                         theSprite^.speed.v := -abs(theSprite^.speed.v);
  196.                 end;
  197.             4: 
  198.                 begin
  199.                     GetGridRect(p3, gridRect);
  200.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  201.                         theSprite^.speed.h := -abs(theSprite^.speed.h)
  202.                     else
  203.                         theSprite^.speed.v := abs(theSprite^.speed.v);
  204.                 end;
  205.             8: 
  206.                 begin
  207.                     GetGridRect(p4, gridRect);
  208.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  209.                         theSprite^.speed.h := -abs(theSprite^.speed.h)
  210.                     else
  211.                         theSprite^.speed.v := -abs(theSprite^.speed.v);
  212.                 end;
  213. { Sides}
  214.             3: {left}
  215.                 begin
  216.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  217.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  218.                 end;
  219.             5: { top}
  220.                 begin
  221.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  222.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  223.                 end;
  224.             10: { bottom}
  225.                 begin
  226.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  227.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  228.                 end;
  229.             12: { right}
  230.                 begin
  231.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  232.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  233.                 end;
  234.  
  235. { three corners}
  236.             7: {bottom right free}
  237.                 begin
  238.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  239.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  240.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  241.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  242.                 end;
  243.             11: { top right free}
  244.                 begin
  245.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  246.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  247.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  248.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  249.                 end;
  250.             13: { bottom left free}
  251.                 begin
  252.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  253.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  254.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  255.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  256.                 end;
  257.             14: { top left free}
  258.                 begin
  259.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  260.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  261.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  262.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  263.                 end;
  264.             6: { diagonal}
  265.                 begin
  266.                     if theSprite^.speed.h + theSprite^.speed.v > 0 then { if down-right speed}
  267.                         begin
  268.                             theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  269.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  270.                             theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  271.                             theSprite^.speed.v := -abs(theSprite^.speed.v);
  272.                         end
  273.                     else { else up-left speed}
  274.                         begin
  275.                             theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  276.                             theSprite^.speed.h := abs(theSprite^.speed.h);
  277.                             theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  278.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  279.                         end;
  280.                 end;
  281.             9: { diagonal}
  282.                 begin
  283.                     if theSprite^.speed.h - theSprite^.speed.v > 0 then { if up-right speed}
  284.                         begin
  285.                             theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  286.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  287.                             theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  288.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  289.                         end
  290.                     else { else down-left speed}
  291.                         begin
  292.                             theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  293.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  294.                             theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  295.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  296.                         end;
  297.                 end;
  298.         end; {case}
  299.         theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);
  300.         theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);
  301.     end; (*GridTest*)
  302.  
  303.     var
  304.         firstFace, secondFace, thirdFace: GrafPtr;
  305.  
  306.     procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
  307. {    theSprite->speed.v++; // Simple gravity}
  308.     begin
  309.         theSprite^.fixedPointPosition.h := theSprite^.fixedPointPosition.h + theSprite^.speed.h;
  310.         theSprite^.fixedPointPosition.v := theSprite^.fixedPointPosition.v + theSprite^.speed.v;
  311.         theSprite^.position.h := BSR(theSprite^.fixedPointPosition.h, 4);
  312.         theSprite^.position.v := BSR(theSprite^.fixedPointPosition.v, 4);
  313.         GridTest(theSprite);
  314.         if KeepOnScreenFixed(theSprite) then
  315.             ;
  316.     end; (*MoveSpriteInGrid*)
  317.  
  318.  
  319. {Standard rect-based bounce-off collision handling.}
  320. {VAD ÄR DETTA FÖR SKIT???}
  321. {This routine seems to have been left here by mistake. I'll nuke it when I feel 100% sure.}
  322.     procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr);
  323.         var
  324.             tempSpeed: Integer;
  325.     begin
  326.         if RectSeparate(SpritePtr(theSprite), SpritePtr(anotherSprite), kPushBoth) >= 2 then { 2 or 3: horizontal, otherwise vertical}
  327.             begin
  328.                 tempSpeed := theSprite^.speed.h;
  329.                 theSprite^.speed.h := anotherSprite^.speed.h;
  330.                 anotherSprite^.speed.h := tempSpeed;
  331.                 theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);
  332.             end
  333.         else
  334.             begin
  335.                 tempSpeed := theSprite^.speed.v;
  336.                 theSprite^.speed.v := anotherSprite^.speed.v;
  337.                 anotherSprite^.speed.v := tempSpeed;
  338.                 theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);
  339.             end;
  340.     end; (*HitSprite*)
  341.  
  342.  
  343.     procedure DrawAllTiles;
  344.         var
  345.             h, v: Integer;
  346.     begin
  347.         for h := 0 to kArraySizeH - 1 do
  348.             for v := 0 to kArraySizeV - 1 do
  349.                 DrawTile(h, v);
  350.     end; {DrawAllTiles}
  351.  
  352. end.